﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AzureProvider.ssdsClient;
using System.ServiceModel;
using System.Collections.Specialized;

namespace AzureProvider.SoupMethods
{
    public abstract class BaseMethods
    {
        protected abstract string containerId {get;}
        protected abstract string kind { get; }
        protected abstract Entity CreateEntity(object Object);
        public abstract object CreateObject(Entity Entity);

        protected  SitkaSoapServiceClient CreateSoapClient(out Scope scope)
        {
            BasicHttpBinding binding = new BasicHttpBinding();
            binding.MaxReceivedMessageSize = 4194304;
            binding.ReaderQuotas.MaxStringContentLength = 4194304;
            binding.Security.Mode = BasicHttpSecurityMode.Transport;
            binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
            binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
            binding.Security.Transport.Realm = "";
            binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
            var client = new SitkaSoapServiceClient(binding, new EndpointAddress("https://data.database.windows.net/soap/v1"));
          
            //var client = new SitkaSoapServiceClient();

            var config = SsdsConfig.Create();

            scope = new Scope();
            scope.AuthorityId = config.Authority;
            scope.ContainerId = containerId;

            client.ClientCredentials.UserName.UserName = config.Username;
            client.ClientCredentials.UserName.Password = config.Password;

            return client;

        }
        public static NameValueCollection StringDictionary2NameValueCollection(StringDictionary StringDictionary)
        {
            NameValueCollection NameValueCollection = new NameValueCollection();
            foreach (string key in StringDictionary.Keys )
            {
                NameValueCollection.Add(key, StringDictionary[key]);
            }

            return NameValueCollection;

        }
        public static void CreateAuthority(out string errMessage)
        {
            errMessage = null;
            var client = new SitkaSoapServiceClient();

            try
            {
                var config = SsdsConfig.Create();

                client.ClientCredentials.UserName.UserName = config.Username;
                client.ClientCredentials.UserName.Password = config.Password;

                // To target the "service" level you use the "empty" scope.
                Scope scope = new Scope();

                // Create authority
                Authority authority = new Authority();
                authority.Id = config.Authority;
                client.Create(scope, authority);
            }
            catch (FaultException<Error> ex)
            {
                errMessage = ex.Detail.Message;
            }
            finally
            {
                client.Abort();
            }
        }

        public static void DeleteAuthority(out string errMessage)
        {
            throw new NotImplementedException("Not Surpport.");
        }


        public static void CreateContainer(string containerId,out string errMessage)
        {
            errMessage = null;
            var client = new SitkaSoapServiceClient();

            try
            {
                var config = SsdsConfig.Create();

                client.ClientCredentials.UserName.UserName = config.Username;
                client.ClientCredentials.UserName.Password = config.Password;

                // Identify scope. To create a container authority must be in scope.
                Scope scope = new Scope();
                scope.AuthorityId = config.Authority;

                // Create a container
                Container container = new Container();
                container.Id = containerId;
                client.Create(scope, container);
            }
            catch (FaultException<Error> ex)
            {
                errMessage = ex.Detail.Message;
            }
            finally
            {
                client.Abort();
            }
        }


     public static void DeleteContainer(string containerId,out string errMessage)
        {
            errMessage = null;
            var client = new SitkaSoapServiceClient();

            try
            {
                var config = SsdsConfig.Create();

                client.ClientCredentials.UserName.UserName = config.Username;
                client.ClientCredentials.UserName.Password = config.Password;

                // Identify scope. To create a container authority must be in scope.
                Scope scope = new Scope();
                scope.AuthorityId = config.Authority;
                scope.ContainerId = containerId;
                client.Delete (scope);
            }
            catch (FaultException<Error> ex)
            {
                errMessage = ex.Detail.Message;
            }
            finally
            {
                client.Abort();
            }
        }



        public void Insert(object myObj, out string errMessage)
        {
            Scope scope;
            var client = CreateSoapClient(out scope);
            errMessage = null;
            try
            {
                client.Create(scope, CreateEntity(myObj));

                client.Close();
            }
            catch (FaultException<Error> ex)
            {
                errMessage = ex.Detail.Message;
            }
            finally
            {
                client.Abort();
            }

        }
        public void Update(object myObj, out string errMessage)
        {
            Scope scope;
            var client = CreateSoapClient(out scope);
            errMessage = null;

            try
            {
                Entity Ent =CreateEntity(myObj);
                scope.EntityId=Ent.Id;
                client.Update(scope,Ent);

                client.Close();
            }
            catch (FaultException<Error> ex)
            {
                errMessage = ex.Detail.Message;
            }
            finally
            {
                client.Abort();
            }

        }

        public List<Entity> GetEntities(string query, out string errMessage)
        {
            Scope scope;
            var client = CreateSoapClient(out scope);
            errMessage = null;

            try
            {
                //default a query if none specified
                var qry = String.IsNullOrEmpty(query) ? "from e in entities where e.Kind == \"" + kind + "\" select e" : query;

                //make the actual query to SSDS
                var entities = client.Query(scope, qry);                

                client.Close();

                return entities;
            }
            catch (FaultException<Error> ex)
            {
                errMessage = ex.Detail.Message;
            }
            finally
            {
                client.Abort();
            }
            return null;

        }

        public IEnumerable<Object> GetObjects(string query, out string errMessage)
        {
            Scope scope;
            var client = CreateSoapClient(out scope);
            errMessage = null;

            try
            {
                //default a query if none specified
                var qry = String.IsNullOrEmpty(query) ? "from e in entities where e.Kind == \"" + kind + "\" select e" : query;
                
                //make the actual query to SSDS
                var entities = client.Query(scope, qry);

                 var myObjs =entities.ConvertAll<object>(CreateObject);

                ////construct the Task objects from SSDS
                //var myObjs = from t in entities
                //            select CreateObject(t);

                client.Close();

                return myObjs;
            }
            catch (FaultException<Error> ex)
            {
                errMessage = ex.Detail.Message;
            }
            finally
            {
                client.Abort();
            }
            return null;

        }

        public Object GetObject(string Id, out string errMessage)
        {
            return CreateObject(GetEntity(Id, out errMessage));
        }

        public Entity GetEntity(string Id, out string errMessage)
        {
            Scope scope;
            var client = CreateSoapClient(out scope);
            errMessage = null;

            try
            {
                //default a query if none specified
                var qry = string.Format("from e in entities where e.Kind == \"{0}\" && e.Id==\"{1}\" select e", kind, Id);

                //make the actual query to SSDS
                var entities = client.Query(scope, qry);

                client.Close();

                return entities.First();
            }
            catch (FaultException<Error> ex)
            {
                errMessage = ex.Detail.Message;
            }
            finally
            {
                client.Abort();
            }
            return null;
        }

        public  void Delete(string entityId)
        {
            Scope scope;
            var client = CreateSoapClient(out scope);

            try
            {
                scope.EntityId = entityId;
                client.Delete(scope);
                client.Close();
            }
            catch (FaultException<Error> ex)
            {
                if (ex.Detail.StatusCode != ErrorCodes.EntityNotFound)
                    throw;
            }
            finally
            {
                client.Abort();
            }
        }
    }
}
